{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# `Nuqleon.Linq.Expressions.Bonsai.Serialization`\n",
        "\n",
        "Provides serialization of Bonsai expressions in JSON and binary form."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Reference the library"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Option 1 - Use a local build\n",
        "\n",
        "If you have built the library locally, run the following cell to load the latest build."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "#r \"bin/Debug/net6.0/Nuqleon.Linq.Expressions.Bonsai.Serialization.dll\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Option 2 - Use NuGet packages\n",
        "\n",
        "If you want to use the latest published package from NuGet, run the following cell."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "#r \"nuget:Nuqleon.Linq.Expressions.Bonsai.Serialization,*-*\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## (Optional) Attach a debugger\n",
        "\n",
        "If you'd like to step through the source code of the library while running samples, run the following cell, and follow instructions to start a debugger (e.g. Visual Studio). Navigate to the source code of the library to set breakpoints."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "System.Diagnostics.Debugger.Launch();"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Expression Serialization using Bonsai\r\n",
        "\r\n",
        "Expression trees can be serialized to the JSON-based Bonsai format using the `BonsaiExpressionSerializer` class. First, we'll create a simple expression tree and convert it to the `ExpressionSlim` representation."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Lambda(MemberAccess(System.String.Length, Parameter(System.String, s)), Parameter(System.String, s))\r\n"
          },
          "output_type": "unknown"
        }
      ],
      "source": [
        "using System.Linq.Expressions;\r\n",
        "\r\n",
        "Expression<Func<string, int>> expr = s => s.Length;\r\n",
        "\r\n",
        "var slim = expr.ToExpressionSlim();\r\n",
        "\r\n",
        "Console.WriteLine(slim);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "To serialize this expression tree, we can use the simplest overload of the `BonsaiExpressionSerializer`, as shown below. By calling the `Serialize` method, we obtain a `string` holding the Bonsai JSON-based format."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "{\"Context\":{\"Members\":[[\"P\",0,\"Length\",[],2]],\"Types\":[[\"::\",\"System.String\",0],[\"::\",\"System.Func`2\",0],[\"::\",\"System.Int32\",0],[\"<>\",1,[0,2]]],\"Assemblies\":[\"System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e\"],\"Version\":\"0.9.0.0\"},\"Expression\":[\"=>\",3,[\".\",0,[\"$\",0,0]],[[0,\"s\"]]]}\r\n"
          },
          "output_type": "unknown"
        }
      ],
      "source": [
        "using System.Linq.Expressions.Bonsai.Serialization;\r\n",
        "\r\n",
        "var ser = new BonsaiExpressionSerializer();\r\n",
        "\r\n",
        "string json = ser.Serialize(slim);\r\n",
        "\r\n",
        "Console.WriteLine(json);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "In order to inspect the Bonsai tree in some more detail, we'll use the `PrettyPrinter` type from `Nuqleon.Json`, and print the tree again."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "{\r\n  \"Context\": {\r\n    \"Members\": [\r\n      [\r\n        \"P\",\r\n        0,\r\n        \"Length\",\r\n        [\r\n          \r\n        ],\r\n        2\r\n      ]\r\n    ],\r\n    \"Types\": [\r\n      [\r\n        \"::\",\r\n        \"System.String\",\r\n        0\r\n      ],\r\n      [\r\n        \"::\",\r\n        \"System.Func`2\",\r\n        0\r\n      ],\r\n      [\r\n        \"::\",\r\n        \"System.Int32\",\r\n        0\r\n      ],\r\n      [\r\n        \"<>\",\r\n        1,\r\n        [\r\n          0,\r\n          2\r\n        ]\r\n      ]\r\n    ],\r\n    \"Assemblies\": [\r\n      \"System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e\"\r\n    ],\r\n    \"Version\": \"0.9.0.0\"\r\n  },\r\n  \"Expression\": [\r\n    \"=>\",\r\n    3,\r\n    [\r\n      \".\",\r\n      0,\r\n      [\r\n        \"$\",\r\n        0,\r\n        0\r\n      ]\r\n    ],\r\n    [\r\n      [\r\n        0,\r\n        \"s\"\r\n      ]\r\n    ]\r\n  ]\r\n}\r\n"
          },
          "output_type": "unknown"
        }
      ],
      "source": [
        "using Json = Nuqleon.Json.Expressions;\r\n",
        "\r\n",
        "var print = new Json.PrettyPrinter();\r\n",
        "\r\n",
        "string pretty = print.Visit(Json.Expression.Parse(json));\r\n",
        "\r\n",
        "Console.WriteLine(pretty);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "From a top-level point of view, a Bonsai tree consists of two sections:\r\n",
        "\r\n",
        "* `Context` which holds information about assemblies, types, and members.\r\n",
        "* `Expression` which resembles a LISP S-expression where every node of an expression tree is represented as a JSON array whose first element is a discriminator.\r\n",
        "\r\n",
        "Taking a closer look, our expression looks like:\r\n",
        "\r\n",
        "```json\r\n",
        "[\r\n",
        "    \"=>\",\r\n",
        "    3,\r\n",
        "    [\r\n",
        "        \".\",\r\n",
        "        0,\r\n",
        "        [\"$\", 0, 0]\r\n",
        "    ],\r\n",
        "    [\r\n",
        "        [0, \"s\"]\r\n",
        "    ]\r\n",
        "]\r\n",
        "```\r\n",
        "\r\n",
        "The top-level node is of type `=>` which represents a lambda and consists of three elements:\r\n",
        "\r\n",
        "* `3` represents the type of the lambda, which corresponds to index `3` in the `Types` table in the context, which we'll look at in a moment;\r\n",
        "* the body of the lambda;\r\n",
        "* an array of parameters to the lambda.\r\n",
        "\r\n",
        "Starting from the parameters at the end, we have an array with a single element `[0, \"s\"]`. In here, `s` is the name of the parameter, and `0` is the type, which is again an entry in the `Types` tables in the context. Looking at the `Types` table, we can see four entries:\r\n",
        "\r\n",
        "```json\r\n",
        "    [\"::\", \"System.String\", 0],\r\n",
        "    [\"::\", \"System.Func`2\", 0],\r\n",
        "    [\"::\", \"System.Int32\", 0],\r\n",
        "    [\"<>\", 1, [0, 2]]\r\n",
        "```\r\n",
        "\r\n",
        "The first three entries are all of type `::` which denotes a *simple type*, which is just a type with a name located in an assembly with the specified index, in all cases above `0`, which corresponds to the `Assemblies` table's first entry:\r\n",
        "\r\n",
        "```\r\n",
        "    \"System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e\"\r\n",
        "```\r\n",
        "\r\n",
        "> **Note**: Assemblies are just a .NET artifact but Bonsai trees can also run on different platforms, e.g. be bound to a C++ runtime, get evaluated in JavaScript, etc. For interoperability purposes, one often erases assemblies for well-known identifiers that are agreed upon by all target systems (e.g. `STD` to represent a standard library).\r\n",
        "\r\n",
        "Back to our type table, we have three simple types, for `String`, `Func<,>`, and `Int32`. The fourth type is of type `<>` and reperesents a closed generic type:\r\n",
        "\r\n",
        "```json\r\n",
        "    [\"<>\", 1, [0, 2]]\r\n",
        "```\r\n",
        "\r\n",
        "This notation means that we're closing over the open generic type at index `1` in the table (`Func<,>`) using type arguments at index `0` (`String`) and index `2` (`Int32`). As a result, this fourth entry in the type table (i.e. at index `3`) represents `Func<String, Int32>`, which is indeed the type of the lambda. Armed with this knowledge, we can also decipher the parameter `[0, \"s\"]` whose type is at index `0` (`String`).\r\n",
        "\r\n",
        "```json\r\n",
        "[\r\n",
        "    \"=>\",\r\n",
        "    3, // Func<string, int>\r\n",
        "    [\r\n",
        "        \".\",\r\n",
        "        0,\r\n",
        "        [\"$\", 0, 0]\r\n",
        "    ],\r\n",
        "    [\r\n",
        "        [0 /* string */, \"s\"]\r\n",
        "    ]\r\n",
        "]\r\n",
        "```\r\n",
        "\r\n",
        "Finally, we can have a look at the body of the lambda:\r\n",
        "\r\n",
        "```json\r\n",
        "    [\r\n",
        "        \".\",\r\n",
        "        0,\r\n",
        "        [\"$\", 0, 0]\r\n",
        "    ]\r\n",
        "```\r\n",
        "\r\n",
        "This node's discriminator is `.` which denotes member lookup. The next array slot contains the member from the `Members` table, which contains:\r\n",
        "\r\n",
        "```json\r\n",
        "    [\"P\", 0, \"Length\", [], 2]\r\n",
        "```\r\n",
        "\r\n",
        "In here, `P` stands for property, which consists of a declaring type (`0` in the `Types` table, i.e. `String`), a name (`Length`), indexer parameters (none), and the return type (`2` in the `Types` table, i.e. `Int32`).\r\n",
        "\r\n",
        "Finally, the last array slow in the member lookup node is `[\"$\", 0, 0]`, which is a variable reference denoted by `$`. The indexes `0` and `0` refer to the scope and the index of the variable in that scope. In this case, the immediately surrounding scope is the lambda, whose first parameter is `string s`, so this expression node refers to that variable."
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": ".NET (C#)",
      "language": "C#",
      "name": ".net-csharp"
    },
    "language_info": {
      "file_extension": ".cs",
      "mimetype": "text/x-csharp",
      "name": "C#",
      "pygments_lexer": "csharp",
      "version": "9.0"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}